/*
    A program for the MSP430FG4618 on the Experimenter's board to accept I2C information from the touchpad,
    display it numerically on the LCD, and send it to a host PC for graphical display.

    Steve Underwood 
*/

#include <stdint.h>
#include <msp430xG46x.h>

#define FALSE 0
#define TRUE (!FALSE)

//First blank, and the hex codes, which all display quite
//well on a 7-segment display.
#define CHAR_SPACE          0
#define CHAR_ALL            (SEG_a|SEG_b|SEG_c|SEG_d|SEG_e|SEG_f|SEG_g|SEG_h)
#define CHAR_0              (SEG_a|SEG_b|SEG_c|SEG_d|SEG_e|SEG_f)
#define CHAR_1              (SEG_b|SEG_c)
#define CHAR_2              (SEG_a|SEG_b|SEG_d|SEG_e|SEG_g)
#define CHAR_3              (SEG_a|SEG_b|SEG_c|SEG_d|SEG_g)
#define CHAR_4              (SEG_b|SEG_c|SEG_f|SEG_g)
#define CHAR_5              (SEG_a|SEG_c|SEG_d|SEG_f|SEG_g)
#define CHAR_6              (SEG_a|SEG_c|SEG_d|SEG_e|SEG_f|SEG_g)
#define CHAR_7              (SEG_a|SEG_b|SEG_c)
#define CHAR_8              (SEG_a|SEG_b|SEG_c|SEG_d|SEG_e|SEG_f|SEG_g)
#define CHAR_9              (SEG_a|SEG_b|SEG_c|SEG_d|SEG_f|SEG_g)
#define CHAR_A              (SEG_a|SEG_b|SEG_c|SEG_e|SEG_f|SEG_g)
#define CHAR_B              (SEG_c|SEG_d|SEG_e|SEG_f|SEG_g)
#define CHAR_C              (SEG_a|SEG_d|SEG_e|SEG_f)
#define CHAR_D              (SEG_b|SEG_c|SEG_d|SEG_e|SEG_g)
#define CHAR_E              (SEG_a|SEG_d|SEG_e|SEG_f|SEG_g)
#define CHAR_F              (SEG_a|SEG_e|SEG_f|SEG_g)
#define CHAR_MINUS          (SEG_g)

#define SEG_a       0x01
#define SEG_b       0x02
#define SEG_c       0x04
#define SEG_d       0x08
#define SEG_e       0x40
#define SEG_f       0x10
#define SEG_g       0x20
#define SEG_h       0x80

#define LCD_MEM_OFFSET  2   //offset from LCDMEM[0]
#define LCD_MEM_LOC    11   //num of LCDMEM[] locations used

const uint8_t lcd_digit_table[18] =
{
    CHAR_0,
    CHAR_1,
    CHAR_2,
    CHAR_3,
    CHAR_4,
    CHAR_5,
    CHAR_6,
    CHAR_7,
    CHAR_8,
    CHAR_9,
    CHAR_A,
    CHAR_B,
    CHAR_C,
    CHAR_D,
    CHAR_E,
    CHAR_F,
    CHAR_MINUS,
    CHAR_SPACE
};

void clrLCD(void)
{
  for( int i = LCD_MEM_OFFSET; i < (LCD_MEM_OFFSET + LCD_MEM_LOC); i++)
  {
    LCDMEM[i] = 0;
  }
}

void init_lcd(void)
{
    int i;

    /* Basic timer setup */
    /* Set ticker to 32768/(256*256) */
    BTCTL = BT_fCLK2_DIV128 | BT_fCLK2_ACLK_DIV256;

    for (i = 0;  i < 20;  i++)
        LCDMEM[i] = 0;

    /* Turn on the COM0-COM3 and R03-R33 pins */
    P5SEL |= (BIT4 | BIT3 | BIT2);
    P5DIR |= (BIT4 | BIT3 | BIT2);

    /* LCD-A controller setup */
    LCDACTL = LCDFREQ_128 | LCD4MUX | LCDSON | LCDON;
    LCDAPCTL0 = LCDS0 | LCDS4 | LCDS8 | LCDS12 | LCDS16 | LCDS20 | LCDS24;
    LCDAPCTL1 = 0;
    LCDAVCTL0 = LCDCPEN;
    LCDAVCTL1 = 1 << 1;
}

void LCDchar(int ch, int pos)
{
    /* Put a segment pattern at a specified position on the LCD display */
    LCDMEM[9 - pos] = ch;
}

void LCDdigit(uint16_t val, int pos)
{
    LCDchar(lcd_digit_table[val], pos);
}

void LCDdec(uint16_t val, int pos)
{
    int i;

    for (i = 2;  i >= 0;  i--)
    {
        LCDchar(lcd_digit_table[val%10], pos + i);
        val /= 10;
    }
}

void configure_uart_usci0(void)
{
    /* Configure USCI0A as a UART */

    /* Configure the port with the reset bit held high */
    UCA0CTL1 |= UCSWRST;
    
    P2SEL |= (BIT4 | BIT5);

    UCA0CTL0 = 0;                   /* 8-bit character */
    UCA0CTL1 = UCSSEL_2;            /* SMCLK */

    /* Set the bit rate registers for 115200 baud */
    UCA0BR0 = 9;
    UCA0BR1 = 0;
    UCA0MCTL = UCBRS_1;

    UCA0STAT = 0;
    UCA0TXBUF = 0;

    UCA0CTL1 &= ~UCSWRST;
}

void configure_i2c_usci0(void)
{
    /* Configure USCI0B as an I2C port */
    P3SEL |= (BIT2 | BIT1);
    UCB0CTL1 |= UCSWRST;                    /* Enable SW reset */

    UCB0CTL0 = UCMODE_3 | UCSYNC;           /* I2C Slave, synchronous mode */
    UCB0I2COA = 0x48;                       /* Own Address */
    UCB0CTL1 &= ~UCSWRST;                   /* Clear SW reset, resume operation */
    UCB0I2CIE |= (UCSTPIE | UCSTTIE);       /* Enable STT and STP interrupt */
    IE2 |= UCB0RXIE;                        /* Enable RX interrupt */
}

void writeToInfoMem(uint8_t valueToWrite);
uint8_t ReadFromInfoMem(uint16_t* flashPtr);
void PortsInit(void);

void writeToInfoMem(uint8_t valueToWrite)
{
    uint16_t* FlashPtrForWrite;     //initialize flash pointer
    
    FlashPtrForWrite = (uint16_t*)0x01800;  //select address in info. memory
    
    __disable_interrupt();  //disable/re-enable interrupts
    
    FCTL3 = FWKEY;          //Clear Lock bit (unlock flash)
    FCTL1 = FWKEY + ERASE;  //Set Erase bit
    
    *FlashPtrForWrite = 0;  //Dummy write to erase Flash word
    
    FCTL1 = FWKEY + WRT;    //Set WRT bit for write operation
                            //(enable flash write)
    
    *FlashPtrForWrite = valueToWrite; //write last LCD value to flash
    
    FCTL1 = FWKEY;          //Clear WRT bit (disable flash write)
    FCTL3 = FWKEY + LOCK;   //Set LOCK bit (lock flash)
    
}

uint8_t ReadFromInfoMem(uint16_t* flashPtr)
{
  uint8_t valueToRead = 0;
  
  __disable_interrupt();  //disable interrupts
     
  valueToRead = *flashPtr;
  return valueToRead;
}

void PortsInit(void)
{
 P1OUT = 0;
 P1DIR = 0xFF & ~(BIT0|BIT1);
 P1SEL = BIT1; 
}

uint8_t valueToLCD = 0; 
uint8_t valueFromFlash = 0; 
    
void main(void)
{

    uint16_t* flashPtrForRead;
    flashPtrForRead = (uint16_t*)0x01800;
    
    WDTCTL = WDTPW | WDTHOLD;           /* Stop watchdog */
    
    configure_uart_usci0();
    configure_i2c_usci0();
    FLL_CTL0 = XCAP14PF;		// Configure load caps (14pF)
    PortsInit();			// Initialize ports
    init_lcd();
    
    _EINT();
    
    //Start timer: ACLK, divide by 8, continuous mode, clear
    TACTL = TASSEL_1 | ID_3 | MC_2 | TACLR ; 
    TACCTL0 = CCIE;	// Enable interrupts on Compare 0
    
    for (;;)
    {
#if 1
        /* Normal operation */
          valueFromFlash = ReadFromInfoMem(flashPtrForRead);  //read from flash
          LCDdec(valueFromFlash, 3);  //display value retrieved from flash
          _EINT();    //enable interrupts
          writeToInfoMem(valueToLCD); //write value to flash
          LCDdec(valueToLCD, 3);     
          _EINT();    //enable interrupts
          LPM0;
 //         clrLCD();
       //   LPM0;
#else
        /* Checking out the host interface */
        UCA0TXBUF = valueToLCD++;
        {
          long int i;
          for (i = 0;  i < 10000;  i++)
              _NOP();
        }
#endif
    }
}

#pragma vector = USCIAB0TX_VECTOR
__interrupt void USCIAB0TX_ISR(void)
{
    valueToLCD =
    UCA0TXBUF = UCB0RXBUF;
}

#pragma vector = USCIAB0RX_VECTOR
__interrupt void USCIAB0RX_ISR(void)
{
    UCB0STAT &= ~(UCSTPIFG | UCSTTIFG);
    LPM0_EXIT;
}

#pragma vector = TIMERA0_VECTOR
__interrupt void timera0_interrupt(void)
{
   LPM0_EXIT;  
   clrLCD();
}

